package com.example.myapplication2;

import java.nio.*;
import java.lang.*;
import java.util.*;
import java.nio.channels.*;

class sendMapV {
    public byte[] data = new byte[0];
    boolean got = false;
    int sendTime = 0;
}

public class base {
    SocketChannel dataSock, numSock;
    int oneLen;
    int numPort, dataPort;
    myBuf wrietBuf = new myBuf(1000), wrietBuf2 = new myBuf(1000);
    byte[] key = helpFunc.con_key;
    long sendPos = 0, peerPos = 0, recvPos = 0;
    int packSendTime = helpFunc.con_packEffectTime;
    long lastPackCreateTime = System.currentTimeMillis();
    Map<Long, sendMapV> sendMap = new HashMap<Long, sendMapV>();
    int rNet = 0, wNet = 0, maxGotLen = 0, maxSenLen = 0;
    int timeoutInter = helpFunc.con_timeoutInternal;
    float gotRate = 1;
    int maxAskTime = calAskTime();
    ServerSocketChannel dataS, numS;
    long lastRecvTime = System.currentTimeMillis();

    base(int oneLen_a) throws Exception {
        sendMap.put((long) 0, new sendMapV());
        oneLen = oneLen_a;
        iniSock();
    }

    int calAskTime() {
        if (gotRate > 0.9)
            return 2;
        if (gotRate > 0.75)
            return 3;
        if (gotRate > 0.5)
            return 4;
        if (gotRate > 0.25)
            return 5;
        if (gotRate > 0.1)
            return 8;
        return 20;
    }

    void reFreshSendMap() {
        if (sendMap.get(sendPos).data.length == 0)
            return;
        if (System.currentTimeMillis() > lastPackCreateTime + packSendTime) {
            sendPos++;
            sendMap.put(sendPos, new sendMapV());
            lastPackCreateTime = System.currentTimeMillis();
        }
    }


    void dealFd(SelectableChannel channel, SelectionKey key) throws Exception {
        if (channel == dataSock && key.isReadable())
            dealDataRecv();
        else if (channel == dataSock && key.isWritable()) {
            int ll = wrietBuf.size();
            byte[] peerBuf = helpFunc.tcpWrite(dataSock, wrietBuf.get());
            wrietBuf.set(peerBuf);
            wNet += ll - peerBuf.length;
        } else if (channel == numSock && key.isWritable()) {
            byte[] peerBuf = helpFunc.tcpWrite(numSock, wrietBuf2.get());
            wrietBuf2.set(peerBuf);
        }
    }

    void tellAddBuf(int l) {
        wrietBuf2.writeDWord(l);
    }

    void rig(Selector s) throws Exception {
        if (wrietBuf.size() > 0)
            dataSock.register(s, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        else
            dataSock.register(s, SelectionKey.OP_READ);
        if (wrietBuf2.size() > 0)
            numSock.register(s, SelectionKey.OP_WRITE);
    }

    long calWaitTime() {
        if (sendMap.get(sendPos).data.length == 0)
            return timeoutInter;
        long t = lastPackCreateTime + packSendTime - System.currentTimeMillis();
        if (t > timeoutInter)
            return timeoutInter;
        if (t <= 0)
            return 1;
        return t;
    }

    void dealDataRecv() throws Exception {
        byte[] r = helpFunc.tcpRead(dataSock);
        rNet += r.length;
        if (r.length + sendMap.get(sendPos).data.length >= oneLen)
            lastPackCreateTime = System.currentTimeMillis();
        int pos = 0;
        while (true) {
            int ll = oneLen - sendMap.get(sendPos).data.length;
            if (r.length >= pos + ll) {
                byte[] temp = new byte[oneLen];
                System.arraycopy(sendMap.get(sendPos).data, 0,
                        temp, 0, sendMap.get(sendPos).data.length);
                System.arraycopy(r, pos,
                        temp, sendMap.get(sendPos).data.length, ll);
                pos += ll;
                sendMap.get(sendPos).data = temp;
                sendPos++;
                sendMap.put(sendPos, new sendMapV());
            } else {
                byte[] temp = new byte[sendMap.get(sendPos).data.length + r.length - pos];
                System.arraycopy(sendMap.get(sendPos).data, 0,
                        temp, 0, sendMap.get(sendPos).data.length);
                System.arraycopy(r, pos,
                        temp, sendMap.get(sendPos).data.length, r.length - pos);
                sendMap.get(sendPos).data = temp;
                break;
            }
        }
    }

    void iniSock() throws Exception {
        dataS = ServerSocketChannel.open();
        dataPort = helpFunc.bindAnyPort(dataS);
        numS = ServerSocketChannel.open();
        numPort = helpFunc.bindAnyPort(numS);
    }

    void doAccept() throws Exception {
        dataSock = dataS.accept();
        numSock = numS.accept();
        dataSock.configureBlocking(false);
        numSock.configureBlocking(false);
        helpFunc.print("conn");
    }
}
